#! /usr/bin/python

__author__="joepearson"
__date__ ="$May 5, 2011 2:56:31 PM$"

from PyQt4 import QtGui, QtCore
import pypm

class AddMIDIForwardWindow(QtGui.QWidget):
    """
    Dialog for adding a forwarding rule.
    """

    def __init__(self, owner):
        super(AddMIDIForwardWindow, self).__init__()

        self.owner = owner
        # Get a list of available MIDI devices.
        self.MIDIDevices = {} # an empty dictionary.
        self.refreshMIDIDevices()

        # Available MIDI message types:

        self.MIDIMessageTypes = {'Note On':'noteOn', 'Note Off': 'noteOff',
            'Polyphonic Key Pressure':'polyKeyPressure', 'CC Change':'ccChange',
            'Program Change':'progChange', 'Channel Pressure':'channelPressure',
            'Pitch Wheel':'pitchWheel'}

        self.forwardTypes = ['MIDI', 'OSC']

        # This is true if the file is run separately.
        
        self.initUI()

    def refreshMIDIDevices(self):
        """
        Get a list of available MIDI output devices.  This is then used
        to populate self.deviceCombo.
        """
        # Reset the internal list.
        self.MIDIDevices = {}

        for id in range(pypm.CountDevices()):
            devInfo = pypm.GetDeviceInfo(id)

            if devInfo[3]:
                # If it's an output device.
                self.MIDIDevices[devInfo[1]] = id

        print "Adding output devices:", self.MIDIDevices

    def cancel(self):
        """
        Called when the user cancels the addition of a forwarding rule.
        """
        self.owner.stack.setCurrentIndex(0)

    def addRule(self):
        """
        Called when the user choosed to add a new forwarding rule.
        """

        returnDict = {}

        returnDict['ruleType'] = str(self.typeCombo.currentIndex())

        returnDict['fromAddress'] = str(self.fromEdit.displayText())

        returnDict['toAddress'] = str(self.toAddressEdit.displayText())

        returnDict['hostname'] = str(self.hostEdit.displayText())

        returnDict['port'] = str(self.portEdit.displayText())

        currentlySelected = str(self.deviceCombo.currentText())
        returnDict['device'] = self.MIDIDevices[currentlySelected]

        returnDict['channel'] = str(self.channelCombo.currentText())

        currentMessage = str(self.messageCombo.currentText())
        returnDict['message'] = self.MIDIMessageTypes[currentMessage]

        returnDict['data1'] = str(self.data1Edit.displayText())
        returnDict['data2'] = str(self.data2Edit.displayText())

        self.owner.addForwardRule(returnDict)
        self.owner.stack.setCurrentIndex(0)

    def keyPressEvent(self, event):
        """
        Override the default handler so that the user can press return or
        escape.
        """
        if event.key() == QtCore.Qt.Key_Escape:
            self.cancel()
        elif event.key() == QtCore.Qt.Key_Enter:
            self.addRule()

    def validate(self, index):
        """
        Disable/Enable controls depending on whether the user chooses
        to create a MIDI or an OSC rule.
        """
        # MIDI rules == 0
        # OSC rules == 1

        if index == 0:
            # A MIDI rule.

            # Disable OSC
            self.toAddressLabel.setVisible(False)
            self.toAddressEdit.setVisible(False)

            self.hostLabel.setVisible(False)
            self.hostEdit.setVisible(False)

            self.portLabel.setVisible(False)
            self.portEdit.setVisible(False)

            # Enable MIDI
            self.deviceCombo.setVisible(True)
            self.deviceLabel.setVisible(True)

            self.channelCombo.setVisible(True)
            self.channelLabel.setVisible(True)

            self.messageCombo.setVisible(True)
            self.messageLabel.setVisible(True)

            self.data1Edit.setVisible(True)
            self.data1Label.setVisible(True)

            self.data2Edit.setVisible(True)
            self.data2Label.setVisible(True)

        elif index == 1:
            # An OSC Rule, so do the opposite.

            # Enable OSC
            self.toAddressLabel.setVisible(True)
            self.toAddressEdit.setVisible(True)

            self.hostLabel.setVisible(True)
            self.hostEdit.setVisible(True)

            self.portLabel.setVisible(True)
            self.portEdit.setVisible(True)

            # Disable MIDI
            self.deviceCombo.setVisible(False)
            self.deviceLabel.setVisible(False)

            self.channelCombo.setVisible(False)
            self.channelLabel.setVisible(False)

            self.messageCombo.setVisible(False)
            self.messageLabel.setVisible(False)

            self.data1Edit.setVisible(False)
            self.data1Label.setVisible(False)

            self.data2Edit.setVisible(False)
            self.data2Label.setVisible(False)


    def initUI(self):

        # Labels
        self.oscAddrLabel = QtGui.QLabel('OSC Address')
        self.typeLabel = QtGui.QLabel('Forwarding Type')
        self.toAddressLabel = QtGui.QLabel('To OSC Address')
        self.hostLabel = QtGui.QLabel('Host')
        self.portLabel = QtGui.QLabel('Port')
        self.deviceLabel = QtGui.QLabel('Device')
        self.channelLabel = QtGui.QLabel('Channel')
        self.messageLabel = QtGui.QLabel('Message')
        self.data1Label = QtGui.QLabel('Data1')
        self.data2Label = QtGui.QLabel('Data2')

        # Inputs
        self.fromEdit = QtGui.QLineEdit()
        self.typeCombo = QtGui.QComboBox(self)
        self.toAddressEdit = QtGui.QLineEdit()
        self.hostEdit = QtGui.QLineEdit()
        self.portEdit = QtGui.QLineEdit()
        self.deviceCombo = QtGui.QComboBox(self)
        self.channelCombo = QtGui.QComboBox(self)
        self.messageCombo = QtGui.QComboBox(self)
        self.data1Edit = QtGui.QLineEdit()
        self.data2Edit = QtGui.QLineEdit()

        # Buttons
        self.cancelButton = QtGui.QPushButton('Cancel')
        self.addButton = QtGui.QPushButton('Add')

        # Layouts
        self.grid = QtGui.QGridLayout()
        self.grid.setSpacing(10)

        self.grid.addWidget(self.oscAddrLabel, 1, 0)
        self.grid.addWidget(self.fromEdit, 1, 1)

        self.grid.addWidget(self.typeLabel, 2, 0)
        self.grid.addWidget(self.typeCombo, 2, 1)

        self.grid.addWidget(self.toAddressLabel, 3, 0)
        self.grid.addWidget(self.toAddressEdit, 3, 1)

        self.grid.addWidget(self.hostLabel, 4, 0)
        self.grid.addWidget(self.hostEdit, 4, 1)

        self.grid.addWidget(self.portLabel, 5, 0)
        self.grid.addWidget(self.portEdit, 5, 1)

        self.grid.addWidget(self.deviceLabel, 6, 0)
        self.grid.addWidget(self.deviceCombo, 6, 1)

        self.grid.addWidget(self.channelLabel, 7, 0)
        self.grid.addWidget(self.channelCombo, 7, 1)

        self.grid.addWidget(self.messageLabel, 8, 0)
        self.grid.addWidget(self.messageCombo, 8, 1)

        self.grid.addWidget(self.data1Label, 9, 0)
        self.grid.addWidget(self.data1Edit, 9, 1)

        self.grid.addWidget(self.data2Label, 10, 0)
        self.grid.addWidget(self.data2Edit, 10, 1)

        self.grid.addWidget(self.cancelButton, 11, 0)
        self.grid.addWidget(self.addButton, 11, 1)

        # Connections

        # Type combo box
        self.connect(self.typeCombo, QtCore.SIGNAL('activated(int)'),
            self.validate)

        # Buttons
        self.connect(self.addButton, QtCore.SIGNAL('clicked()'),
            self.addRule)
        self.connect(self.cancelButton, QtCore.SIGNAL('clicked()'),
            self.cancel)



        # Add some stuff to the combo boxes.

        # Types
        for type in self.forwardTypes:
            self.typeCombo.addItem(type)

        # devices
        for device in self.MIDIDevices.keys():
            # Add to the list.
            self.deviceCombo.addItem(device)

        # channel
        for channel in range(16):
            self.channelCombo.addItem(str(channel+1))

        # messages
        for message in self.MIDIMessageTypes.keys():
            # Add to the list
            self.messageCombo.addItem(message)


        # Add some default values
        self.fromEdit.setText('/example/osc/address')
        self.portEdit.setText('10000')
        self.data1Edit.setText('60')
        self.data2Edit.setText('%oscdata')

        self.setLayout(self.grid)

        self.setWindowTitle("Add MIDI Forwarding Rule")

        # Prevent user resize
        #self.resize(450, 300)
        #self.setFixedSize(self.size().width(), self.size().height())

        self.validate(self.typeCombo.currentIndex())



if __name__ == "__main__":
    # If running standalone, run the UI in test mode.
    
    # only needs importing if running alone
    import sys
    
    app = QtGui.QApplication(sys.argv)
    mw = AddMIDIForwardWindow(app)
    mw.show()
    sys.exit(app.exec_())
